#pragma once
#include <iostream>
#include <queue>
#include <functional>
#include "Thread.hpp"
#include "ThreadPool.hpp"
#include "log.hpp"
#include "LockGuard.hpp"
#include <unistd.h>

static const int defaultnum = 5;

class ThreadData
{
};

template <typename T>
class ThreadPool
{
private:
    ThreadPool(const ThreadPool<T> &th) = delete;
    const ThreadPool<T> operator=(const ThreadPool<T> &th) = delete;

    ThreadPool(int thread_num = defaultnum)
        : _thread_nums(thread_num)
    {
        // 初始化锁和条件变量
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);

        // 先构建若干线程
        for (int i = 0; i < _thread_nums; i++)
        {
            // 创建线程并放入 容器中
            std::string threadname = "Thread-" + std::to_string(i + 1);

            T td;
            Thread<T> t(std::bind(&ThreadPool::ThreadRun, this, std::placeholders::_1), threadname, td);
            // Thread 的构造函数第一个参数为 指定调用函数，后面是函数名

            _threads.push_back(t);
        }
    }
    ~ThreadPool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }

public:
    void ThreadWait()
    {
        pthread_cond_wait(&_cond, &_mutex);
    }

    void ThreadWakeup()
    {
        pthread_cond_signal(&_cond);
    }

    // 线程需要处理的任务
    void ThreadRun(T &data) // 这个参数暂时没有用到
    {
        while (true)
        {
            T t;
            {
                LockGuard LockGuard(&_mutex);
                //   pthread_mutex_lock(&_mutex);
                // std::cout << "Thread is running ..." << endl;

                while (_q.empty())
                { // 如果任务队列为空，那么在条件上进行等待
                    // pthread_cond_wait(_cond, &mutex);

                    ThreadWait();
                }
                t = _q.front(); // 拿任务
                _q.pop();

                // pthread_mutex_unlock(&_mutex);
            }

            // 运行任务
            t();

            // cout << "result: " << t.PrintResult() << endl;
        }
    }

    bool Start()
    {
        // 启动
        for (auto &thread : _threads)
        {
            thread.Start();
        }
        return 1;
    }

    void Push(const T &in)
    {
        {
            LockGuard lockguard(&_mutex);
            _q.push(in);
            ThreadWakeup();
        }
    }

    void Wait()
    {
        for (auto &thread : _threads)
        {
            thread.Join();
        }
    }

    static ThreadPool<T> *GetInstance() // 饿汉模式
    {
        if (_instance == nullptr)
        {
            LockGuard lockguard(&sig_lock);

           
            if (_instance == nullptr)
            {
                 lg.LogMessage(Info, "创建单例成功!");
                _instance = new ThreadPool<T>();
            }
        }
        return _instance;
    }

private:
    std::queue<T> _q;
    std::vector<Thread<T>> _threads; // 放线程
    int _thread_nums;
    pthread_mutex_t _mutex;
    pthread_cond_t _cond;

    static ThreadPool<T> *_instance; //= nullptr; // 单例指针
    // 类内初始化静态成员时需要constexpr,但是该变量必须是常量,或者用const修饰

    static pthread_mutex_t sig_lock; //= PTHREAD_MUTEX_INITIALIZER;
    // 在多线程下获取 GetInstance()  是有风险的，所以需要一把全局的锁将GetInstance 进行封锁
    // 这个初始化也可以在类外进行，此时就无需 constexpr


    
    // load   定义负载负载，如果线程不够，可以动态增加，线程等待过多，可以释放掉一些资源
    // int numeber{1};

    // int _thread_num_low_water;  // 进程数量低水位线
    // int _thread_num_high_water; // 进程数量高水位线

    // int _task_num_low_water; // 任务数量低水位线
    // int _task_num_high_wate; // 任务数量低水位线
};



// 也可以在类外进行初始化
template <typename T>
ThreadPool<T> *ThreadPool<T>::_instance = nullptr;

template <typename T>
pthread_mutex_t ThreadPool<T>::sig_lock = PTHREAD_MUTEX_INITIALIZER;
